﻿#include "tcpclient.h"

#include <QSettings>
#include <QApplication>
#include <QAbstractSocket>

TcpClient::TcpClient(QObject *parent) :
    QObject(parent),
    m_pClientSocket(NULL),
    m_pConnectCheckTimer(NULL),
    m_connected(0),
    m_pConnectDetectThread(NULL),
    m_pConnectDetect(NULL),
    m_detect(0),
    m_localip(DEF_LOCAL_IP),
    m_localport(DEF_LOCAL_PORT),
    m_serverip(DEF_SERVER_IP),
    m_serverport(DEF_SERVER_PORT)
{
    m_pClientSocket = new QBindTcpSocket(this);
    m_pClientSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
    connect(m_pClientSocket, SIGNAL(readyRead()), this, SLOT(receiveServerData()));
    connect(m_pClientSocket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(displaySocketError(QAbstractSocket::SocketError)));
    //    connect(m_pClientSocket, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(netStateChanged(QAbstractSocket::SocketState)));

    m_pConnectCheckTimer = new QTimer(this);
    connect(m_pConnectCheckTimer, SIGNAL(timeout()), this, SLOT(connectCheck()));


    m_pConnectDetectThread = new QThread();
}

TcpClient::~TcpClient()
{
    m_pConnectCheckTimer->stop();
    delete m_pConnectCheckTimer;

    m_pClientSocket->disconnectFromHost();
    m_pClientSocket->waitForDisconnected();
    m_pClientSocket->close();
    delete m_pClientSocket;

    if (m_connected != 0)
    {
        m_pConnectDetectThread->quit();
        m_pConnectDetectThread->wait();
    }

    delete m_pConnectDetectThread;
}

void TcpClient::setConfigFileName(QString configfilename)
{
    m_configFileName = configfilename;
}

void TcpClient::connectToServer()
{
    if (m_pClientSocket == NULL)
    {
        qDebug() << "m_pClientSocket not alloc";
        return;
    }

    if (m_connected == 0)
    {
        loadIpAndPort();
        if (m_pConnectDetect == NULL)
        {
            m_pConnectDetect = new TcpConnectDetect;
        }
        qDebug() << "ConnectToServer";
        qDebug() << "localip=" << m_localip << "localport=" << m_localport;
        qDebug() << "serverip=" << m_serverip << "serverport=" << m_serverport;

        m_pConnectDetect->setIpAndPort(m_localip, m_localport, m_serverip, m_serverport);

        m_pConnectDetect->moveToThread(m_pConnectDetectThread);

        connect(this, SIGNAL(siDetectHost()), m_pConnectDetect, SLOT(connectDetect()), Qt::QueuedConnection);
        connect(m_pConnectDetect, SIGNAL(siConnectSta(int)), this, SLOT(detectStatus(int)), Qt::QueuedConnection);

        // 20191226由于检测线程会造成网络重连，所以将检测线程注释 lft
/*
        connect(m_pConnectDetectThread, SIGNAL(started()), m_pConnectDetect, SLOT(detectStart()) );
        connect(m_pConnectDetectThread, SIGNAL(finished()), m_pConnectDetect, SLOT(deleteLater()) );  // 退出删除对象

        m_pConnectDetectThread->start();    // 启动线程
*/
        m_pConnectCheckTimer->start(1000);
        m_connected = 1;
        m_detect = 1;
    }
}

void TcpClient::disConnectFromServer()
{
    if (m_connected != 0)
    {
        m_pConnectCheckTimer->stop();

        if (m_pClientSocket != NULL)
        {
            m_pClientSocket->disconnectFromHost();
            m_pClientSocket->waitForDisconnected();
            m_pClientSocket->close();
        }

        m_pConnectDetectThread->quit();
        m_pConnectDetectThread->wait();

        m_connected = 0;
        m_detect = 0;
    }
}

void TcpClient::loadIpAndPort()
{
    if (!m_configFileName.isEmpty())
    {
        // 机器的IP和端口 和 连接机器的本地IP和端口
        QSettings configIni(m_configFileName, QSettings::IniFormat);
        QString serverip, localip;
        quint16 serverport, localport;

        serverip = configIni.value("server/ip", QVariant("192.168.16.253")).toString();
        serverport = configIni.value("server/port", QVariant(5000)).toInt();
        localip = configIni.value("local/ip", QVariant("192.168.16.41")).toString();
        localport = configIni.value("local/port", 5001).toInt();

        // 回写参数
        configIni.setValue("server/ip", serverip);
        configIni.setValue("server/port", serverport);
        configIni.setValue("local/ip", localip);
        configIni.setValue("local/port", localport);

        m_localip = localip;
        m_localport = localport;
        m_serverip = serverip;
        m_serverport = serverport;
    }
}

// 发送数据的槽
void TcpClient::slotSendData(QByteArray dat)
{
    if (m_pClientSocket != NULL)
    {
        m_pClientSocket->write(dat);
    }
}

// 自动检测连接
void TcpClient::connectCheck()
{
    if (m_pClientSocket == NULL)
    {
        qDebug() << "Socket is not alloced";
        return;
    }

//  qDebug() << "check client connect";
    if (m_connected == 1)
    {
        if (m_localip.isEmpty() == false)
        {
            m_pClientSocket->bindAddrAndPort(m_localip, m_localport);
        }
        m_pClientSocket->abort();
        m_pClientSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
        m_pClientSocket->connectToHost(m_serverip, m_serverport);
        int rslt = m_pClientSocket->waitForConnected(2000);
        if (rslt == 0)
        {

        }
        /*
        qDebug("bind connect and waitForConnected 2000, rslt=%d", rslt);
        qDebug() << "localip=" << m_localip << "localport=" << m_localport;
        qDebug() << "serverip=" << m_serverip << "serverport=" << m_serverport;
        */
        m_connected = 2;
    }
    else if (m_connected != 0)
    {
        switch(m_pClientSocket->state())
        {
            case QAbstractSocket::ConnectedState:
            {
                if (m_connected != 3)
                {
                    /*
                    qDebug() << "net State is Connected";
                    qDebug() << "localip=" << m_localip << "localport=" << m_localport;
                    */
                    m_connected = 3;       // 检测连接状态
                }

                break;
            }
            case  QAbstractSocket::ConnectingState:
            {
                if (m_connected != 2)
                {
                    qDebug() << "net State is Connecting";
                 //   qDebug() << "localip=" << m_localip << "localport=" << m_localport;
                }
                m_connected = 2;
                break;
            }
            case QAbstractSocket::UnconnectedState:
            {
                if (m_connected != 1)
                {
                //    qDebug() << "net State is unconnected";
                //    qDebug() << "localip=" << m_localip << "localport=" << m_localport;
                }
                m_connected = 1;
                break;
            }
            default:
            {
            /*
                QAbstractSocket::HostLookupState
                QAbstractSocket::BoundState
                QAbstractSocket::ListeningState
                QAbstractSocket::ClosingState
            */
                {
                    qDebug("net State is %d\r\n", m_pClientSocket->state());
                    qDebug() << "localip=" << m_localip << "localport=" << m_localport;
                    qDebug() << "serverip=" << m_serverip << "serverport=" << m_serverport;
                }
                m_connected = 1;
            }
        }
    }
    else
    {

    }

    if (m_connected == 3)   // 已连接
    {
        if (m_detect == 1)
        {
         //   qDebug() << "Machine " << QThread::currentThread();
            m_detect = 0;
            emit(siDetectHost());
         //   qDebug() << "after send SiDetectHost ";
        }
    }

    emit (siConnectSta(m_connected));     // 网络连接信号
}

void TcpClient::detectStatus(int sta)
{
  //  qDebug("host detect sta=%d", sta);

    m_detect = 1;
    if (sta == 1)  // 网络已断开
    {
        qDebug("disconnect ClientSocket by detect");
        m_pClientSocket->disconnectFromHost();
//        m_pClientSocket->waitForDisconnected();
        m_pClientSocket->close();
        m_connected = 1;
    }
    else if (sta == 2)     // 网络连接还在
    {

    }
    else
    {

    }
}

void TcpClient::receiveServerData()
{
    if (m_pClientSocket != NULL)
    {
        QByteArray tmpDat;
        tmpDat = m_pClientSocket->readAll(); // 读取
//      qDebug("ReceiveServerData, size = %d", tmpDat.size());
//      PrintAsHex(&tmpDat);

        emit(siReceiveData(tmpDat));          // 发送收到数据信号
    }
}

void TcpClient::displaySocketError(QAbstractSocket::SocketError err)
{
    QString errinfo;

    errinfo.sprintf("Err: code=%d, errorString=", err);
    errinfo += m_pClientSocket->errorString();

//    qDebug() << errinfo;

    emit(siConnectErr(errinfo));    // 网络错误信息
}

void TcpClient::netStateChanged(QAbstractSocket::SocketState sta)
{
    switch (sta)
    {
    /*
    case UnconnectedState:
    case HostLookupState:
    case ConnectingState:
    case ConnectedState:
    case BoundState:
    case ListeningState:
    case ClosingStat:
    */
    default:
        break;
    }

}
void TcpClient::hostFound()
{
    qDebug("found host");


}


#if(0)
//-------------------------------------------------------
TcpConnectDetect::TcpConnectDetect(QObject *parent) :
    QObject(parent),
    m_pDetectSocket(NULL),
    m_localip(DEF_LOCAL_IP),
    m_localport(DEF_LOCAL_PORT),
    m_serverip(DEF_SERVER_IP),
    m_serverport(DEF_SERVER_PORT)
{
}

TcpConnectDetect::~TcpConnectDetect()
{
    if (m_pDetectSocket == NULL)
    {
        m_pDetectSocket->disconnectFromHost();
        m_pDetectSocket->waitForDisconnected();
        m_pDetectSocket->close();
        delete m_pDetectSocket;
    }
}

void TcpConnectDetect::detectStart()
{
    qDebug("TcpConnectDetect start");
    if (m_pDetectSocket == NULL)
    {
        m_pDetectSocket = new QBindTcpSocket;
    }
}

int TcpConnectDetect::connectDetect()
{
    int connectsta = 0;
    int rslt;

 //   qDebug() << "TcpConnectDetect " << QThread::currentThread();

    if (m_pDetectSocket == NULL)
    {
        return 0;
    }
    if (m_localip.isEmpty() == false)
    {
        m_pDetectSocket->bindAddrAndPort(m_localip, m_localport);
    }
    m_pDetectSocket->abort();
    m_pDetectSocket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
    m_pDetectSocket->connectToHost(m_serverip, m_serverport);

    do
    {
        rslt = m_pDetectSocket->waitForConnected(4000);     // 等待连接

        qDebug("bind Detect connect rslt=%d", rslt);
        qDebug() << "localip=" << m_localip << "localport=" << m_localport;
        qDebug() << "serverip=" << m_serverip << "serverport=" << m_serverport;

        switch(m_pDetectSocket->state())
        {
        case QAbstractSocket::ConnectedState:
        {
            // 如果连接上，说明 m_pClientSocket 连接已经无效, 需要断开重新连接
            // 先断开测试连接
            m_pDetectSocket->disconnectFromHost();
            m_pDetectSocket->waitForDisconnected();
            connectsta = 1;
            // 发送断开主连接的信号
            qDebug() << "detect is Connected, disconnect all";

            break;
        }
        case QAbstractSocket::UnconnectedState:
        {
        //    qDebug() << "detect is Unconnected err=" << m_pDetectSocket->error() << ", info:" << m_pDetectSocket->errorString();

            switch (m_pDetectSocket->error())
            {
               case QAbstractSocket::SocketTimeoutError:      // 连接超时，说明已经断开
               case QAbstractSocket::NetworkError:            // 网络错误, 主机不可连接, 可能已经断开
               {
                    qDebug() << "detect is timout, disconnect all";
                    connectsta = 1;
                    // 发送断开主连接的信号
                    break;
               }
               case QAbstractSocket::ConnectionRefusedError:  // 拒绝连接, 说明连接还在
               {
                   connectsta = 2;
               //    qDebug() << "Connection Refused, old connect is alive";
                   break;
               }
                /*
                    case QAbstractSocket::RemoteHostClosedError:
                    case QAbstractSocket::HostNotFoundError:
                    case QAbstractSocket::SocketAccessError:
                    case QAbstractSocket::SocketResourceError:
                    case QAbstractSocket::SocketTimeoutError:
                    case QAbstractSocket::DatagramTooLargeError:
                    case QAbstractSocket::AddressInUseError:
                    case QAbstractSocket::SocketAddressNotAvailableError:
                    case QAbstractSocket::UnsupportedSocketOperationError:
                    case QAbstractSocket::UnfinishedSocketOperationError:
                    case QAbstractSocket::ProxyAuthenticationRequiredError:
                    case QAbstractSocket::SslHandshakeFailedError:
                    case QAbstractSocket::ProxyConnectionRefusedError:
                    case QAbstractSocket::ProxyConnectionClosedError:
                    case QAbstractSocket::ProxyConnectionTimeoutError:
                    case QAbstractSocket::ProxyNotFoundError:
                    case QAbstractSocket::ProxyProtocolError:
                    case QAbstractSocket::UnknownSocketError:
                    */
               default:
               {
                   // 继续检测
                   connectsta = 2;
                   qDebug() << " retry";
                   break;
               }
            }   // 错误处理结束
        }
        case QAbstractSocket::ConnectingState:
        {
         //   qDebug() << "detect is Connecting";
            //   qDebug() << "localip=" << m_localip << "localport=" << m_localport;
            // 继续等待
            break;
        }
        case QAbstractSocket::HostLookupState:
        case QAbstractSocket::BoundState:
        case QAbstractSocket::ListeningState:
        case QAbstractSocket::ClosingState:
        default:
        {
            // 继续等待
            qDebug("detect sta is %d\r\n", m_pDetectSocket->state());
            break;
        }
        }

        if (connectsta != 0)
        {
            break;
        }

    }while(1);


    m_pDetectSocket->close();

    // 发送本次测试连接的状态信号
    emit(siConnectSta(connectsta));
    return connectsta;
}

void TcpConnectDetect::setIpAndPort(QString localip, quint16 localport, QString serverip, quint16 serverport)
{
    m_localip    = localip;
    m_localport  = localport;
    m_serverip   = serverip;
    m_serverport = serverport;
}
#endif






